/**
 * vim: tabstop=4
 * 
 * @license		http://www.gnu.org/licenses/gpl.html GPL Version 3
 * @author		Ian Moore <imooreyahoo@gmail.com>
 * @copyright	Copyright (c) 2011 Ian Moore
 *
 * This file is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This file is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this file. If not, see <http://www.gnu.org/licenses/>.
 */
// require("js/omv/NavigationPanel.js")
// require("js/omv/data/DataProxy.js")
// require("js/omv/FormPanelExt.js")
// require("js/omv/form/PasswordField.js")
// require("js/omv/form/plugins/FieldInfo.js")
// require("js/omv/Window.js")
// require("js/omv/data/DataRequest.js")
// require("js/omv/util/Format.js")

Ext.ns("OMV.Module.Services");

// Register the menu.
OMV.NavigationPanelMgr.registerMenu("services", "cups", {
	text: "Printing",
	icon: "images/cups.png"
});

/**
 * @class OMV.Module.Services.Cups
 * @derived OMV.FormPanelExt
 */
OMV.Module.Services.Cups = function(config) {
	var initialConfig = {
		rpcService: "cups",
		layout: "vbox",
		layoutConfig: {
			align: "stretch"
		},
		id: 'OMV.Module.Services.CupsConfigPanel'
	};
	Ext.apply(initialConfig, config);
	OMV.Module.Services.Cups.superclass.constructor.call(this, initialConfig);
};
Ext.extend(OMV.Module.Services.Cups, OMV.FormPanelExt, {

	initComponent : function() {
		
		
		OMV.Module.Services.Cups.superclass.initComponent.apply(
		  this, arguments);
		
		// update fields
		this.on("load", this._updateFormFields, this);
		
		// Fill printers onload
		this.on("load", function(fpanel, data) {

			if(data.enable) {
				
				Ext.getCmp('OMV-Module-Services-CUPSJobsGridPanel').enable();
				Ext.getCmp('OMV.Module.Services.CUPSInfoPanel').enable();
				if(data.enable_samba) {
					Ext.getCmp('OMV.Module.Services.CUPSInfoPanel-smb').show();
				} else {
					Ext.getCmp('OMV.Module.Services.CUPSInfoPanel-smb').hide();
				}
				
				
			} else {
				Ext.getCmp('OMV-Module-Services-CUPSJobsGridPanel').disable();
				Ext.getCmp('OMV.Module.Services.CUPSInfoPanel').disable();
			}
			
			// Each printer
			var mstore = Ext.getCmp('OMV.Module.Services.Cups-printers-grid').getStore();
			mstore.removeAll();

			var pPanel = this;
			
			this.ippList = new Array();
			this.smbList = new Array();
			
			Ext.each(data.printers, function(f) {
				
                mstore.add([
                    new Ext.data.Record(f)
                ]);
				
				pPanel.ippList[pPanel.ippList.length] ='http://'+location.hostname+':631/printers/'+f['uuid'];
				pPanel.smbList[pPanel.smbList.length] = '\\\\'+location.hostname+'\\'+f['uuid'];
	
			});

			if(this.ippList.length == 0) this.ippList[0] = 'NONE';
			if(this.smbList.length == 0) this.smbList[0] = 'NONE';
			
			
			// Display propagation message?
			if(this._printersChanged && data.smbenabled && data.enable_samba) {
				
				this._printersChanged = false;
				
				Ext.MessageBox.show({

					title: "SMB/CIFS Shared Printers",
					msg: "This change may take a few minutes to propagate " +
						"to SMB/CIFS service clients. You may restart the SMB/CIFS service "+
						"now to force immediate propagation, but doing so will interrupt SMB/CIFS "+
						"communications for connected clients.<br /><br />Restart the SMB/CIFS service now?",
						
					buttons: Ext.MessageBox.YESNO,
					fn: function(answer) {

						if (answer == "no")
							return;
						
						var onsubmit = function(id, response, error) {
							OMV.MessageBox.updateProgress(1);
							OMV.MessageBox.hide();
							if (error !== null) {
								OMV.MessageBox.error(null, error);
							}
						}

						// Display waiting dialog
						OMV.MessageBox.wait(null, "Restarting SMB/CIFS service ...");

						OMV.Ajax.request(onsubmit, this, "cups",
							"restartSamba", [ ]);			

					},
					scope: this,
					icon: Ext.MessageBox.QUESTION
				});	

			}

		});

	},

	/**
	 * Show property dialog for selected printer
	 */
	editPrinter: function(pname) {

		var win = new OMV.CfgObjectDialog({
			title: "Edit Printer",
			uuid: pname,
            rpcService: "cups",
            rpcSetMethod: "cupsSetPrinter",
            rpcGetMethod: "cupsGetPrinter",
			width: 500,
			height: 200,
			listeners: {
                submit: function() {
                    this.doReload();
                },
                scope: this
            },			
			getFormItems : function() {
				return [{
					xtype: "textfield",
					name: "uuid",
					fieldLabel: "Name",
					readOnly: true
				},{
					xtype: "textfield",
					name: "PrinterInfo",
					fieldLabel: "Description",
					plugins: [ OMV.form.plugins.FieldInfo ],
					infoText: 'Human-readable description such as "HP LaserJet with Duplexer"',
					allowBlank: false
				},{
					xtype: "textfield",
					name: "PrinterLocation",
					fieldLabel: "Location",
					plugins: [ OMV.form.plugins.FieldInfo ],
					infoText: 'Human-readable location such as "Lab 1"'
				}]
			}
		});
		
		win.show();

	},

	/**
	 * Send a test page to the selected printer
	 */
	printTestPage: function(pname) {
		
		var onsubmit = function(id, response, error) {
			OMV.MessageBox.updateProgress(1);
			OMV.MessageBox.hide();
			if (error === null) {
				OMV.MessageBox.info(null,"A test page has been sent to the printer.")
			} else {
				OMV.MessageBox.error(null, error);
			}
		}

		// Display waiting dialog
		OMV.MessageBox.wait(null, "Printing test page ...");

		OMV.Ajax.request(onsubmit, this, "cups",
			"cupsPrintTestPage", [ pname ]);								

	},

	/**
	 * Resume printing
	 */
	resumePrinting: function(pname) {

		var onsubmit = function(id, response, error) {
			OMV.MessageBox.updateProgress(1);
			OMV.MessageBox.hide();
			if (error !== null) {
				OMV.MessageBox.error(null, error);
			}
			Ext.getCmp('OMV.Module.Services.CupsConfigPanel').doLoad();
		}

		// Display waiting dialog
		OMV.MessageBox.wait(null, "Resuming printer ...");

		OMV.Ajax.request(onsubmit, this, "cups",
			"cupsResumePrinting", [ pname ]);								
		
	},

	/**
	 * Pause printing
	 */
	pausePrinting: function(pname) {

		var onsubmit = function(id, response, error) {
			OMV.MessageBox.updateProgress(1);
			OMV.MessageBox.hide();
			if (error !== null) {
				OMV.MessageBox.error(null, error);
			}
			Ext.getCmp('OMV.Module.Services.CupsConfigPanel').doLoad();
		}

		// Display waiting dialog
		OMV.MessageBox.wait(null, "Pausing printer ...");

		OMV.Ajax.request(onsubmit, this, "cups",
			"cupsPausePrinting", [ pname ]);								
		
	},
	
	/**
	 * Cancel all jobs on the selected printer
	 */
	cancelJobs: function(pname) {
		
		Ext.MessageBox.show({

			title: "Confirmation",
			msg: "Are you sure you want to cancel all printing jobs on "+pname+"?",
			buttons: Ext.MessageBox.YESNO,
			fn: function(answer) {

				if (answer == "no")
					return;
												
				var onsubmit = function(id, response, error) {
					OMV.MessageBox.updateProgress(1);
					OMV.MessageBox.hide();
					if (error === null) {
						Ext.getCmp('OMV.Module.Services.CupsConfigPanel').doLoad();
					} else {
						OMV.MessageBox.error(null, error);
					}
				}

				// Display waiting dialog
				OMV.MessageBox.wait(null, "Cancelling jobs ...");

				OMV.Ajax.request(onsubmit, this, "cups",
					"cupsCancelJobs", [ pname ]);								

			},
			scope: this,
			icon: Ext.MessageBox.QUESTION
		});	
	},
	
	/**
	 * Remove the selected printer
	 */
	removePrinter: function(pname) {
		
		Ext.MessageBox.show({

			title: "Confirmation",
			msg: "Are you sure you want to remove the selected printer?",
			buttons: Ext.MessageBox.YESNO,
			fn: function(answer) {

				if (answer == "no")
					return;
												
				var onsubmit = function(id, response, error) {
					OMV.MessageBox.updateProgress(1);
					OMV.MessageBox.hide();
					if (error === null) {
						Ext.getCmp('OMV.Module.Services.CupsConfigPanel')._printersChanged = true;
						Ext.getCmp('OMV.Module.Services.CupsConfigPanel').doLoad();
					} else {
						OMV.MessageBox.error(null, error);
					}
				}

				// Display waiting dialog
				OMV.MessageBox.wait(null, "Removing printer ...");

				OMV.Ajax.request(onsubmit, this, "cups",
					"cupsDeletePrinter", [ pname ]);								

			},
			scope: this,
			icon: Ext.MessageBox.QUESTION
		});	
	},
	
	
	/**
	 * Add a printer to cups. Invokes Wizard to
	 * gather info from user
	 */
	addPrinter : function() {
		
		var pWiz = new OMV.Module.Services.CupsWizard({
			title: 'Add Printer',
			height: 360,
			width: 550,
			method: "cupsAddPrinter",
			afterSubmit: function () {
				
				Ext.getCmp('OMV.Module.Services.CupsConfigPanel')._printersChanged = true;
				Ext.getCmp('OMV.Module.Services.CupsConfigPanel').doLoad();

			},
			steps: [{
				xtype: 'panel',
				items : [{
					html: "<h1>Printer Hardware</h1><br />",
					border: false
				},{
                    border: false,
                    html: "If your printer is not listed here, try Make: Generic, Model: Generic "+
                        "Postscript Printer. If there is more than one driver for your make / model "+
						"choose one that is labeled (recommended) if available, or experiment to find the driver "+
						"that works best for you.<br /><Br />"
				},{
					xtype: 'fieldset',
					layout: 'fit',
					title: "Printer",
					items: [{
						xtype: 'combo',
						name: 'device',
						hiddenName: 'device',
						hideFieldLabel: 'true',
						valueField: 'uuid',
						displayField: 'DeviceInfo',
						emptyText: "Select a printer ...",
						allowBlank: false,
						allowNone: false,
						editable: false,
						triggerAction: "all",
						store: new OMV.data.Store({
							remoteSort: false,
							proxy: new OMV.data.DataProxy("cups", "cupsFindDirectPrinters"),
							reader: new Ext.data.JsonReader({
								idProperty: "uuid",
								fields: [
									{ name: "uuid" }, { name: "DeviceInfo" }
								]
							}),
							listeners: {
								beforeload: function() {
									OMV.MessageBox.wait(null, "Scanning for attached printers ...");
								},
								load: function(s,records) {
									
									OMV.MessageBox.updateProgress(1);
									OMV.MessageBox.hide();
									
									if(!records.length) {
										OMV.MessageBox.error(null,"No printers found.");
										return;
									}
									
									Ext.getCmp('OMV.Module.Services.Cups-make-combo').setDisabled(false);
								}
							}
						}),
						listeners: {
							select: function(s,record) {
								var mm = record.get("DeviceInfo");
								Ext.getCmp('OMV.Module.Services.Cups-name').setValue(mm.replace(/[\s|#|\/]/g, '_'));
								Ext.getCmp('OMV.Module.Services.Cups-description').setValue(mm);
							}
						}
					}]
				},{
					xtype: 'fieldset',
					layout: 'fit',
					title: "Make",
					items: [{
						xtype: 'combo',
						id: 'OMV.Module.Services.Cups-make-combo',
						hideFieldLabel: 'true',
						valueField: 'make',
						displayField: 'make',
						submitValue: false,
						emptyText: "Select a make ...",
						allowBlank: false,
						allowNone: false,
						editable: false,
						triggerAction: "all",
						disabled: true,
						store: new OMV.data.Store({
							remoteSort: false,
							proxy: new OMV.data.DataProxy("cups", "cupsGetMakesModels"),
							reader: new Ext.data.JsonReader({
								idProperty: "make",
								fields: [
									{ name: "make" },
									{ name: "models" }
								]
							})
						}),
						listeners: {
							select: function(s,record) {
								
								var mCombo = Ext.getCmp('OMV.Module.Services.Cups-model-combo');
								mCombo.setDisabled(false);
								mCombo.setValue(null);
								
								var mStore = mCombo.getStore();
								mStore.removeAll();
								Ext.each(record.get('models'), function(m) {
									mStore.add([
										new Ext.data.Record(m)
									]);
								});
							}
						}
					}]
				},{
					xtype: 'fieldset',
					layout: 'fit',
					title: "Model / Driver",
					items: [{
						xtype: 'combo',
						name: 'ppd',
						id: 'OMV.Module.Services.Cups-model-combo',
						hiddenName: 'ppd',
						hideFieldLabel: 'true',
						valueField: 'uuid',
						displayField: 'PpdMakeAndModel',
						emptyText: "Select a model ...",
						allowBlank: false,
						allowNone: false,
						editable: false,
						triggerAction: "all",
						disabled: true,
						mode: "local",
						autoLoad: false,
						store: new Ext.data.SimpleStore({
							fields: [
								{ name: "uuid" },
								{ name: "PpdMakeAndModel" }
							],
							data: [ ]
						})
					}]
				}]
			},{
				xtype: 'panel',
				items : [{
					html: "<h1>Printer Description</h1><br />",
					border: false
				},{
					xtype: "fieldset",
					layout: 'form',
					border: true,
					defaults: { anchor: '100%'},
					items: [{
						xtype: "textfield",
						name: "name",
						id: 'OMV.Module.Services.Cups-name',
						fieldLabel: "Name",
						plugins: [ OMV.form.plugins.FieldInfo ],
						infoText: "May contain any printable characters except \"/\", \"#\", and space",
						vtype: "printername",
						allowBlank: false
					},{
						xtype: "textfield",
						id: 'OMV.Module.Services.Cups-description',
						name: "description",
						fieldLabel: "Description",
						plugins: [ OMV.form.plugins.FieldInfo ],
						infoText: 'Human-readable description such as "HP LaserJet with Duplexer"',
						allowBlank: false
					},{
						xtype: "textfield",
						name: "location",
						fieldLabel: "Location",
						plugins: [ OMV.form.plugins.FieldInfo ],
						infoText: 'Human-readable location such as "Lab 1"'
					}]
				}]
			}]
		});

		pWiz.show();
	},
	
	getFormItems : function() {
		return [{
			xtype: "fieldset",
			title: "General Settings",
			defaults: {
				labelSeparator: ""
			},
			items: [{
				xtype: "checkbox",
				name: "enable",
				fieldLabel: "Enable",
				checked: false,
				inputValue: 1
			},{
				xtype: "numberfield",
				name: "maxjobs",
				fieldLabel: "Max Jobs",
				minValue: 0,
				maxValue: 65535,
				value: 100,
				width: 70,
				allowDecimals: false,
				allowNegative: false,
				plugins: [ OMV.form.plugins.FieldInfo ],
				infoText: "Once the number of print jobs reaches the limit, "+
					"the oldest completed job is automatically purged from the system to make room for the new one. If all of the known jobs are still "+
					"pending or active then the new job will be rejected."
			},{
				xtype: "checkbox",
				name: "enable_samba",
				fieldLabel: "Enable SMB Sharing",
				boxLabel: "Enable sharing of printers over OpenMediaVault's SMB/CIFS service.",
				checked: true,
				inputValue: 1
			},{
				xtype: "checkbox",
				name: "airprint",
				fieldLabel: "Enable AirPrint",
				boxLabel: "<i>Experimental</i>. Provides 'AirPrint' compatibility with Apple iOS devices.",
				checked: false,
				inputValue: 1
			},{
				html: "<br />Users in the <b>lpadmin</b> OpenMediaVault group will "+
					"be able to administer printers using their OpenMediaVault username / password.<br /><br />"
			}]
		},{
			xtype: 'fieldset',
			title: 'Donate',
			items: [{
				html: 'I develop plugins for OpenMediaVault in my spare time, free of charge. If you find this plugin useful, I ask that you please donate.'
			},{
				html: "<div style='margin:10px'><a href='https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=PPYY2F9ST2BAY' target=_blank><img src='images/donate-btn.gif' /></a></div>"
			}]
		},{
			xtype: "panel",
			frame: true,
			title: "Printers",
			layout: 'fit',
			autoScroll: true,
			boxMinHieght: 200,
			flex: 1,
			items: [{
				xtype: "grid",
				autoWidth: true,
				id: 'OMV.Module.Services.Cups-printers-grid',
				loadMask: true,
				boxMinHieght: 200,
				disableLoadMaskOnLoad: false,
				autoScroll: true,
				stripeRows: true,
				columnLines: true,
				layout: "fit",
				border: false,
				stateful: true,
				viewConfig: {
					forceFit: true
				},
				listeners: {
					rowdblclick: function(grid,rowIndex) {
						this.editPrinter(grid.getStore().getAt(rowIndex).get('uuid'));
					},
					scope: this
				},
            	tbar: [{
                	id: "OMV.Module.Services.Cups-printers-grid-add",
	                xtype: "button",
	                text: "Add",
    	            icon: "images/add.png",
					handler: function() {
						this.addPrinter();
					},
					scope: this
				},{
                    id: "OMV.Module.Services.Cups-printers-grid-edit",
                    xtype: "button",
                    text: "Edit",
					disabled: true,
                    icon: "images/edit.png",
					handler: function(b) {
						this.editPrinter(Ext.getCmp('OMV.Module.Services.Cups-printers-grid').getSelectionModel().getSelected().get('uuid'));						
					},
					scope: this
				},{
                    id: "OMV.Module.Services.Cups-printers-grid-remove",
                    xtype: "button",
                    text: "Remove",
					disabled: true,
                    icon: "images/delete.png",
					handler: function(b) {
						this.removePrinter(Ext.getCmp('OMV.Module.Services.Cups-printers-grid').getSelectionModel().getSelected().get('uuid'));
					},
					scope: this
	            },{
					xtype:'tbseparator'
				},{
					xtype: 'button',
					text: "Refresh",
					icon: "images/reload.png",
					handler: function() {
						this.doLoad();
					},
					scope: this
				},{
					xtype:'tbseparator'
				},{
					id: "OMV.Module.Services.Cups-printers-grid-resume",
					xtype:'button',
					disabled: true,
					text: "Resume printing",
					icon: "images/cups_resume.png",
					handler: function(b) {
						this.resumePrinting(Ext.getCmp('OMV.Module.Services.Cups-printers-grid').getSelectionModel().getSelected().get('uuid'));
					},
					scope: this
				},{
					id: "OMV.Module.Services.Cups-printers-grid-pause",
					xtype:'button',
					disabled: true,
					text: "Pause printing",
					icon: "images/cups_pause.png",
					handler: function(b) {
						this.pausePrinting(Ext.getCmp('OMV.Module.Services.Cups-printers-grid').getSelectionModel().getSelected().get('uuid'));
					},
					scope: this
				},{
					xtype:'tbseparator'
				},{
					id: "OMV.Module.Services.Cups-printers-grid-test",
					xtype:'button',
					disabled: true,
					text: "Print test page",
					icon: "images/cups.png",
					handler: function(b) {
						this.printTestPage(Ext.getCmp('OMV.Module.Services.Cups-printers-grid').getSelectionModel().getSelected().get('uuid'));
					},
					scope: this
				},{
					id: "OMV.Module.Services.Cups-printers-grid-jobs",
					xtype:'button',
					disabled: true,
					text: "Cancel Jobs"	,
					icon: "images/trashcan.png",
					handler: function(b) {
						this.cancelJobs(Ext.getCmp('OMV.Module.Services.Cups-printers-grid').getSelectionModel().getSelected().get('uuid'));
					},
					scope: this
				}],
	            viewConfig: { forceFit: true, autoFill: true },
	            sm: new Ext.grid.RowSelectionModel({
	                singleSelect:true,
					listeners: {
						selectionchange: function(sm) {
							var fn = (sm.getSelections().length == 1 ? 'enable' : 'disable');
							Ext.each(['-edit','-remove','-test','-jobs','-pause','-resume'],function(b){
								Ext.getCmp('OMV.Module.Services.Cups-printers-grid'+b)[fn]();
							});
							if(fn == 'enable') {
								switch(sm.getSelected().get('PrinterState')) {
									case 5: // paused
										Ext.getCmp('OMV.Module.Services.Cups-printers-grid-pause').disable();
										break;
									default:
										Ext.getCmp('OMV.Module.Services.Cups-printers-grid-resume').disable();
								}
							}
						}
					}
	            }),
            	store: new Ext.data.SimpleStore({
                	fields: [
						{ name: "uuid" },
						{ name: "PrinterInfo" },
						{ name: "PrinterLocation" },
						{ name: "PrinterMakeAndModel" },
						{ name: "PrinterState" },
						{ name: "PrinterStateMessage" }
					],
               		data: [ ]
            	}),
				columns: [{
					header: "Printer / Queue Name",
					dataIndex: "uuid"
				},{
					header: "Description",
					dataIndex: "PrinterInfo"
				},{
					header: "Location",
					dataIndex: "PrinterLocation"
				},{
					header: "Make and Model / Driver",
					dataIndex: "PrinterMakeAndModel"
				},{
					header: "Status",
					width: 300,
					dataIndex: "PrinterState",
					renderer: function(val, row, record) {
						switch(parseInt(val)) {
							case 3:
								val = "Idle";
								break;
							case 4:
								val = "Processing";
								break;
							case 5:
								val = "Paused";
								break;
							default:
								val = "UNKNOWN";
						}
						var msg = record.get("PrinterStateMessage")
						if(msg) val += " (" + msg + ")";
						return val;
					}
				}]
			}]
		}];
	},

	/**
	 * Private function to update the states of various form fields.
	 */
	_updateFormFields : function() {
		Ext.getCmp('OMV.Module.Services.Cups-printers-grid').setDisabled(!this.findFormField("enable").checked);
	}
});

/**
 * 
 * Printer jobs list grid
 */
OMV.Module.Services.CUPSJobsGridPanel = function(config) {

	var initialConfig = {
		id: 'OMV-Module-Services-CUPSJobsGridPanel',
		disabled: true,
		hideAdd: true,
		hideEdit: true,
		hideDelete: true,
		hideRefresh: false,
		hidePagingToolbar: true,
		viewConfig: { forceFit: true, autoFill: true },
		sm: new Ext.grid.RowSelectionModel({
			singleSelect:true,
			listeners: {
				selectionchange: function(sm) {
					var record = sm.getSelections();
					var fn = 'disable';
					if(record.length == 1) {
						var state = record[0].get("JobState");
						switch(state) {
							case 4:
							case 3:
							case 5:
								fn = 'enable';
						}
					}
					Ext.getCmp("OMV-Module-Services-CUPSJobsGridPanel-cancel-job")[fn]();
				}
			}
		}),
		colModel: new Ext.grid.ColumnModel({
			columns: [{
				header: "Job Id",
				sortable: true,
				dataIndex: "JobId",
				id: "id",
				width: 20,
				renderer: function(val, md, record) {
					return record.get("PrinterUri").replace(/.*\//, '') + ' ' + val;
				}
			},{
				header: "Created",
				sortable: true,
				dataIndex: "TimeAtCreation",
				id: "created",
				renderer: function(val) {
					var myTime = new Date();
					myTime.setTime(val * 1000);
					return myTime.toLocaleString();
				}
			},{
				header: "Name",
				sortable: true,
				dataIndex: "JobName",
				id: "name"
			},{
				header: "User",
				sortable: true,
				dataIndex: "JobOriginatingUserName",
				id: "user",
				width: 40,
				renderer: function(val, md, record) {
					return val + '@' + record.get("JobOriginatingHostName");
				}
			},{
				header: "Size",
				sortable: true,
				dataIndex: "JobKOctets",
				id: "size",
				width: 20,
				renderer: function(val) { return val + 'k'; }
			},{
				header: "Pages",
				sortable: true,
				dataIndex: "JobMediaSheetsCompleted",
				id: "pages",
				width: 20,
				renderer: function(val) {
					return (val ? val : 'Unknown');
				}
			},{
				header: "State",
				sortable: true,
				dataIndex: "JobState",
				id: "State",
				renderer: function(val,md,record) {
					/*
					IPP_JOB_ABORTED = 8
					IPP_JOB_CANCELED = 7
					IPP_JOB_COMPLETED = 9
					IPP_JOB_HELD = 4
					IPP_JOB_PENDING = 3
					IPP_JOB_PROCESSING = 5
					IPP_JOB_STOPPED = 6
					*/
					switch(parseInt(val)) {
						case 8: return 'Aborted';
						case 7: return 'Canceled';
						case 9:
							var myTime = new Date();
							myTime.setTime(record.get("TimeAtCompleted") * 1000);
							return 'Completed ' + myTime.toLocaleString();
						case 4: return 'Held';
						case 3: return 'Pending';
						case 5: return 'Processing';
						case 6: return 'Stopped';
					}
					return 'Unknown ('+val+')';
				}
			}]
		})
	};
	Ext.apply(initialConfig, config);
	OMV.Module.Services.CUPSJobsGridPanel.superclass.constructor.call(
			this, initialConfig);
};

Ext.extend(OMV.Module.Services.CUPSJobsGridPanel, OMV.grid.TBarGridPanel, {

	initComponent : function() {
		
		this.store = new OMV.data.Store({
			autoLoad: false,
			remoteSort: false,
			sortInfo: {
				field: "JobId", direction: "DESC"
			},
			proxy: new OMV.data.DataProxy("cups", "cupsGetJobs", ['not-completed']),
			reader: new Ext.data.JsonReader({
				idProperty: "id",
				totalProperty: "total",
				root: "data",
				fields: [
				         { name: "JobId" },
				         { name: "JobName" },
				         { name: "JobOriginatingUserName" },
						 { name: "JobOriginatingHostName" },
				         { name: "JobKOctets" },
						 { name: "TimeAtCompleted" },
						 { name: "TimeAtCreation" },
						 { name: "JobMediaSheetsCompleted" },
						 { name: "JobState" },
						 { name: "PrinterUri" }
				         ]
			})
		});
		OMV.Module.Services.CUPSJobsGridPanel.superclass.initComponent.
		apply(this, arguments);
	},

	listeners : {
		show: function() {
			this.doLoad();
		}
	},

	initToolbar : function() {
		
		var tbar = OMV.Module.Services.CUPSJobsGridPanel.superclass.initToolbar.apply(this);
		tbar.insert(9,{xtype:'tbseparator'});
		tbar.insert(10,{
			id: "OMV-Module-Services-CUPSJobsGridPanel-cancel-job",
			xtype:'button',
			disabled: true,
			text: "Cancel Job"	,
			icon: "images/trashcan.png",
			handler: function(b) {
				this.cancelJob(Ext.getCmp('OMV-Module-Services-CUPSJobsGridPanel').getSelectionModel().getSelected().get('JobId'));
			},
			scope: this

		});
		tbar.insert(20,{xtype:'tbseparator'});
		tbar.insert(21,{xtype:'tbspacer', width: 20 });
		tbar.insert(22,{
			xtype: "label",
			text: "Show: "
		})
		tbar.insert(23,{xtype:'tbspacer', width: 5 });
		
		tbar.insert(24, {
			xtype: "combo",
			id: "OMV-Module-Services-CUPSJobsGridPanel-statusfilter",
			name: "statusfilter",
			editable: false,
			width: 200,
			autoWidth: false,
			triggerAction: "all",
			autoLoad: true,
			mode: "local",
			store: new Ext.data.SimpleStore({
			   fields: [ "value","text" ],
				  data: [
					[ "all", "All" ],
					[ "not-completed", "Active" ],
					[ "completed", "Completed" ]
				  ]
			}),
			displayField: "text",
			valueField: "value",
			value: "not-completed",
			listeners : {
				select: function(s) {
					var sstore = this.getStore();
					sstore.proxy = new OMV.data.DataProxy("cups", "cupsGetJobs", s.getValue());
					this.doLoad();
				},
				scope: this
			}
		});

		return tbar;
	},
	
	/**
	 * Cancel the selected print job
	 */
	cancelJob: function(jid) {
		
		Ext.MessageBox.show({

			title: "Confirmation",
			msg: "Are you sure you want to cancel the selected printing job?",
			buttons: Ext.MessageBox.YESNO,
			fn: function(answer) {

				if (answer == "no")
					return;
												
				var onsubmit = function(id, response, error) {
					OMV.MessageBox.updateProgress(1);
					OMV.MessageBox.hide();
					if (error === null) {
						Ext.getCmp('OMV-Module-Services-CUPSJobsGridPanel').doLoad();
					} else {
						OMV.MessageBox.error(null, error);
					}
				}

				// Display waiting dialog
				OMV.MessageBox.wait(null, "Cancelling job ...");

				OMV.Ajax.request(onsubmit, this, "cups",
					"cupsCancelJob", [ jid ]);								

			},
			scope: this,
			icon: Ext.MessageBox.QUESTION
		});	

		
	}

});

/**
 * Printer sharing info / howto
 */
OMV.Module.Services.CUPSInfoPanel = function(config) {
	
	var initialConfig = {
		frame: true,
		id: 'OMV.Module.Services.CUPSInfoPanel',
		layout: "form",
		autoScroll: true,
		disabled: true,
        border: false,
		listeners: {
			show: function() {
				var l = Ext.getCmp('OMV.Module.Services.CUPSInfoPanel-ipp-list');
				l.fireEvent("afterrender", l);
                var l = Ext.getCmp('OMV.Module.Services.CUPSInfoPanel-smb-list');
                l.fireEvent("afterrender", l);
			}
		},
		items: [{
			/** IPP shared printer list **/
			xtype: 'fieldset',
			title: 'Internet Printing Protocol (IPP) Shared Printer URLs',
			layout: 'fit',
			items: [{
				xtype: 'box',
				id: 'OMV.Module.Services.CUPSInfoPanel-ipp-list',
				html: '',
				listeners: {
					afterrender: function(t) {
						try {
							t.update(Ext.getCmp('OMV.Module.Services.CupsConfigPanel').ippList.join('<br /><br />'));
						} catch (err) {
						}
					}
				}
			}]
		},{
			/** SMB shared printer list **/
			xtype: 'fieldset',
			id: 'OMV.Module.Services.CUPSInfoPanel-smb',
			title: 'SMB Shared Printer Paths',
			layout: 'fit',
			items: [{
				id: 'OMV.Module.Services.CUPSInfoPanel-smb-list',
				xtype: 'box',
				html: '',
				listeners: {
					afterrender: function(t) {
						try {
							t.update(Ext.getCmp('OMV.Module.Services.CupsConfigPanel').smbList.join('<br /><br />'));
						} catch (err) {
						}
					}
				}
			}]
		},{
			/** Windows sharing INFO **/
			xtype: 'fieldset',
			layout: 'fit',
			title: 'Windows',
			items:[{
				html: 'NOTE: The instructions below may vary slightly depending on the version of Windows on which '+
				'the steps are being performed. Some logical deduction may be required on your part.<br /><br />'+
				'<h1>Internet Printing Protocol (IPP)</h1><br />Printers are shared to Windows via the IPP URL http://'+location.hostname+':631/printers/<i>PRINTER_NAME</i>'+
				'<br /><Br />' +
				'To add an IPP shared printer in Window\'s <b>Control Panel</b> click on <b>Devices and Printers</b> (or Printers and Faxes), click on <b>Add a Printer</b> '+
				'and choose to <B>Add a Network Printer</b>, click on '+
				'<b>The printer that I want isn\'t listed</b> (if a button with that label is presented), then select the option '+
				'labeled <b>Select a shared printer by name</b>. In the text box, you may enter the printer\'s <b>IPP</b> URL as listed above.' +
				'<br /><br />' +
				'<h1>SMB</h1><br />If you have enabled printer sharing over SMB, printers may also be shared to Windows via the SMB path \\\\'+location.hostname+'\\<i>PRINTER_NAME</i>'+
				'<br /><Br />' +
				'To add an SMB shared printer in Window\'s <b>Control Panel</b> click on <b>Devices and Printers</b> (or Printers and Faxes), click on <b>Add a Printer</b> '+
				'and choose to <B>Add a Network Printer</b>, select  <b>Browse for printer</b> (if a button with that label is presented) and select the printer ' +
				'you would like to add. This may prompt you to select or install the printer\'s driver. After you have connected to a shared printer on the network, '+
				'you can use it as if it were attached to your computer. '+
				'<br /><br />'+
				'<h1>Point and Print</h1><br />Drivers can be made available for Windows clients over SMB to enable '+
					'"point-and-print" functionality. When a Windows client initially connects to a printer, '+
					'if a driver is availble, it will automatically be downloaded and installed. To manage the SMB drivers installed on this server, follow these steps '+
					'on a computer running <b>Windows 7 or higher</b>:<br /><br />'+
						'<OL style="list-style: decimal; list-style-image: none; margin-left: 30px;">'+
						'<LI>Click&nbsp;<B>Start</B>, type <b>\\\\'+location.hostname+'</b>, and press Enter. - If prompted to log in, enter the '+
							'user name and password of an OpenMediaVault account that is part of the <b>lpadmin</b> gruop. This will ensure that '+
							'you will have administrative access to printers. You may close the resulting window.</LI>'+
						'<li>Click on <b>Start</b>, type <b>printui /s /c\\\\192.168.1.66</b> , then press enter.</li>'+
						'<LI>Click on the <B>Drivers</B> tab, &nbsp;click <B>Add</B>, and then click <B>Next</B>.</LI>'+
						'<LI>Click to select the&nbsp;check box&nbsp;for&nbsp;the appropriate processor architecture, and then click <B>Next</B>.</LI>'+
						'<LI>Select an in-box driver from the list, and then click <B>Next</B>.&nbsp;&nbsp;&nbsp;-&nbsp;<B>Note</B> '+
						'you may also choose <b>Have Disk</b> and select the driver from the installation media that came '+
						'with the printer.</LI>'+
						'<LI>Click <B>Finish </B>to complete the wizard.</LI></OL><br />'+
						'Subsequent attempts to connect to the printer from a Windows computer should automatically install the appropriate printer driver.'+
										'<br /><br />'

			}]
		},{
			/** OS X sharing INFO **/
			xtype: 'fieldset',
			layout: 'fit',
			title: 'Mac OS X',
			items:[{
				html: 'Shared printers should automatically be available to add in Mac OS X in <b>System Preferences</b> -&gt; <b>Print & Fax</b>. If not, '+
				'you can manually add a printer\'s IPP URL by clicking on <b>IP</b> in the toolbar and selecting the following values:<br /><br /> '+
				'<b>Protocol:</b> Internet Printing Protocol - IPP<br />'+
				'<b>Address:</b> '+location.hostname+'<br />'+
				'<b>Queue:</b> printers/PRINTER_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(be sure to replace <i>PRINTER_NAME</i> with actual name of printer)<br />'+
				'<br />If you have enabled printer sharing over SMB, the printer may also be available in the Windows section of the <b>Print & Fax</b> dialog.'+
				'<br /><Br />'
			}]
		},{
			/** Linux sharing INFO **/
			xtype: 'fieldset',
			layout: 'fit',
			title: 'Linux',
			items:[{
				html: 'Consult your window environment\'s (Gnome, KDE, etc..) or distribution\'s documentation on adding a shared printer. '+
					'Printers shared by this system are discoverable and should appear when Linux searches for networked printers.'
			}]
			
		},{
			/** iOS sharing INFO **/
			xtype: 'fieldset',
			layout: 'fit',
			title: 'AirPrint capable Apple iOS devices',
			items:[{
				html: 'If you have enabled AirPrint support, shared printers should be available in the print dialog of the device.'
			}]

		}]
	};
	Ext.apply(initialConfig, config);
	OMV.Module.Services.CUPSInfoPanel.superclass.constructor.call(
			this, initialConfig);

}
Ext.extend(OMV.Module.Services.CUPSInfoPanel, Ext.Panel, {});



/**
 * Register tabs
 */
OMV.NavigationPanelMgr.registerPanel("services", "cups", {
	title: "Settings",
	cls: OMV.Module.Services.Cups,
	position: 10
});

OMV.NavigationPanelMgr.registerPanel("services", "cups", {
	title: "Jobs",
	cls: OMV.Module.Services.CUPSJobsGridPanel,
	position: 20
});

OMV.NavigationPanelMgr.registerPanel("services", "cups", {
	title: "Printer Sharing",
	cls: OMV.Module.Services.CUPSInfoPanel,
	position: 30
});



/**
 * Wizard for cups actions
 */
OMV.Module.Services.CupsWizard = function(config) {

	// Track the active card in this wizard
	var activeItem = 0;

	var initialConfig = {
		title: 'Wizard',
		modal: true,
		afterSubmit: function() {
			// implementing author will override
		},
		layout: 'fit',
		method: 'none',
		width: 500,
		height: 320,
		items: [{
			xtype: 'form',
			itemId: 'wizardform',
			layout: {
				type: 'card',
				deferredRender : true
			},
			activeItem: 0,
			items: config.steps,
			defaults: {
				border: false,
				bodyStyle: 'padding: 10px;',
				hideMode: 'offsets',
				autoWidth: false,
				anchor: '100%'
			},
			bbar: {
				defaults: { width: 75 },
				items: [{
					xtype: 'tbfill'
				},{
					id: 'card-prev',
					disabled: true,
					itemId: 'prev',
					text: '&laquo; Previous',
					handler: function(b) {
						
						b.ownerCt.ownerCt.layout.setActiveItem(--activeItem);
						
						if(activeItem == 0) b.disable();
						if((activeItem+1) != b.ownerCt.ownerCt.items.length) {
							b.ownerCt.getComponent('next').setText('Next &raquo;');
						}
					}
				},{
					id: 'card-next',
					text: 'Next &raquo;',
					itemId: 'next',
					handler: function(b) {
	
						var pForm = b.findParentByType('form');
						
						// Verify form values
						var fields = pForm.layout.activeItem.findByType(Ext.form.Field);
						pForm.getForm().isValid();
						for(var i = 0; i < fields.length; i++) {
							if(!fields[i].isValid()) return;
						}
						// Submit form
						if((activeItem+1) == b.ownerCt.ownerCt.items.length) {
		
							var wzWindow = pForm.ownerCt;
		
							var onsubmit = function(id, response, error) {
								OMV.MessageBox.updateProgress(1);
								OMV.MessageBox.hide();
								if (error === null) {
									this.afterSubmit(response);
									wzWindow.close();
								} else {
									OMV.MessageBox.error(null, error);
								}
							}
		
							var values = pForm.getForm().getValues();
							
							// Execute RPC
							if(this.cbSubmitHndl) {
								this.cbSubmitHndl(values, wzWindow);
							} else {

								// Display waiting dialog
								OMV.MessageBox.wait(null, "Saving ...");

								OMV.Ajax.request(onsubmit, this, "cups",
									this.method, [ values ]);								
							}
		
							return;
						}
		
						// Go to next card
						pForm.layout.setActiveItem(++activeItem);
						// Clear invalid fields
						Ext.each(pForm.layout.activeItem.findByType(Ext.form.Field),function(f){
							f.clearInvalid();
						});
						
						// Set text to finish?
						if((activeItem+1) == b.ownerCt.ownerCt.items.length) {
							b.setText('Finish');
						}
								
						b.ownerCt.getComponent('prev').enable();
					},
					scope: this
				},{
					id: 'card-cancel',
					text: 'Cancel',
					handler: function() {
						this.close();
					},
					scope: this
				}]
			}
		}]
	}
	Ext.apply(initialConfig, config);
	
	OMV.Module.Services.CupsWizard.superclass.constructor.call(this, initialConfig);
	

}

Ext.extend(OMV.Module.Services.CupsWizard, OMV.Window);

/**
 * Printer names validation
 */
Ext.apply(Ext.form.VTypes, {
	
    printername: function(v) {
        return /^[^\s|#|\\]+$/.test(v);
    },
    printernameText: "Invalid printer name",
    printernameMask: /[^\s|#|\\]/


});

/**
 * Log files
 */


/**
 * @class OMV.Module.Diagnostics.LogPlugin.CUPS
 * @derived OMV.Module.Diagnostics.LogPlugin
 * Class that implements the 'CUPS' log file diagnostics plugin
 */
OMV.Module.Diagnostics.LogPlugin.CUPS = function(config) {
    var initialConfig = {
        title: "Printing Access Log",
        stateId: "c9d06952-00da-11e1-aa29-CUPS",
        columns: [{
            header: "Date & Time",
            sortable: true,
            dataIndex: "date",
            id: "date",
            width: 20,
			renderer: OMV.util.Format.localeTimeRenderer()
		},{
			header: "Host",
			sortable: true,
			dataIndex: "host",
			width: 15
		},{
			header: "User",
			sortable: true,
			width: 15,
			dataIndex: "user"
        },{
            header: "Event",
            sortable: true,
            dataIndex: "event",
            id: "event"
        }],
        rpcArgs: "cupsaccess",
        rpcFields: [
            { name: "date" },
			{ name: "host" },
			{ name: "user" },
            { name: "event" }
        ]
    };
    Ext.apply(initialConfig, config);
    OMV.Module.Diagnostics.LogPlugin.CUPS.superclass.constructor.call(
      this, initialConfig);
};
Ext.extend(OMV.Module.Diagnostics.LogPlugin.CUPS,
  OMV.Module.Diagnostics.LogPlugin, {
});
OMV.preg("log", "cupsaccess", OMV.Module.Diagnostics.LogPlugin.CUPS);

/**
 * @class OMV.Module.Diagnostics.LogPlugin.CUPS-dhcp
 * @derived OMV.Module.Diagnostics.LogPlugin
 * Class that implements the 'CUPS-dhcp' log file diagnostics plugin
 */
OMV.Module.Diagnostics.LogPlugin.CUPSerror = function(config) {
    var initialConfig = {
        title: "Printing Error Log",
        stateId: "c9d06952-00da-11e1-aa29-CUPS-error",
        columns: [{
            header: "Date & Time",
            sortable: true,
            dataIndex: "date",
            id: "date",
            width: 20,
			renderer: OMV.util.Format.localeTimeRenderer()
		},{
            header: "Severity",
            sortable: true,
            dataIndex: "severity",
            id: "severity",
            width: 20,
			renderer: function(val) {
				switch(val) {
					case 'E': return 'Error';
					case 'W': return 'Warning';
					case 'I': return 'Info';
					case 'D': return 'Debug';
				}
				return val;
			}
        },{
            header: "Event",
            sortable: true,
            dataIndex: "event",
            id: "event"
        }],
        rpcArgs: "cupserror",
        rpcFields: [
            { name: "date" },
			{ name: "severity" },
            { name: "event" }
        ]
    };
    Ext.apply(initialConfig, config);
    OMV.Module.Diagnostics.LogPlugin.CUPSerror.superclass.constructor.call(
      this, initialConfig);
};
Ext.extend(OMV.Module.Diagnostics.LogPlugin.CUPSerror,
  OMV.Module.Diagnostics.LogPlugin, {
});
OMV.preg("log", "cupserror", OMV.Module.Diagnostics.LogPlugin.CUPSerror);
